package com.tiny.tinyweb.core.ldap.query;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;

import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;

import com.tiny.tinyweb.core.exception.LdapException;

/**
 * 将 LDAP 条目映射为 {@link java.util.HashMap} 对象的映射器。
 * @see {@link org.springframework.ldap.core.ContextMapper}
 * @author wxiaobin
 */
public class MapMapper implements ContextMapper {
    /**
     * 将 LDAP 条目映射为 {@link java.util.HashMap} 对象，为
     * {@link org.springframework.ldap.core.LdapTemplate}
     * 的 <code>search</code> 处理提供向对象映射的支持。
     * @param object LDAP 条目上下文环境，通常是一个
     * {@link org.springframework.ldap.core.DirContextAdapter} 对象
     * @return 映射后的 {@link java.util.HashMap} 对象
     */
    @Override
	public Object mapFromContext(Object object) {
        // 获取当前条目的所有属性
        NamingEnumeration<? extends Attribute> attrsEnum =
                ((DirContextAdapter) object).getAttributes().getAll();
        // 实例化一个保存条目信息的对象
        Map<String, Object> entry = new HashMap<String, Object>();

        try {
            // 循环条目的所有属性，将该属性包装成一个属性名为键、属性信息为值的 Map 对象
            while (attrsEnum.hasMoreElements()) {
                // 当前属性
                Attribute attrs = attrsEnum.nextElement();
                // 当前属性的所有同名属性（LDAP中可以存在多个同名属性）
                NamingEnumeration<?> valuesEnum = attrs.getAll();
                // 将所有同名属性合并到一个 List 中，单值属性也使用 List 保存
                List<Object> values = new ArrayList<Object>();
                while (valuesEnum.hasMoreElements()) {
                    values.add(valuesEnum.nextElement());
                }
                // 以属性名为键、属性信息为值进行映射
                entry.put(attrs.getID(), values);
            }

            // 返回映射后的 HashMap 对象
            return entry;
        } catch (NamingException ne) {
            // 访问条目属性信息时发生异常
            throw new LdapException(String.format(
                    "Problem creating %1$s from LDAP Entry %2$s",
                    HashMap.class, object), ne);
        }
    }
}
